package com.wh.base.api;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.wh.base.aop.documented.OperLog;
import com.wh.base.api.form.CheckPwdForm;
import com.wh.base.api.form.LoginForm;
import com.wh.base.api.form.ModifyPwdForm;
import com.wh.base.sys.config.service.ConfigService;
import com.wh.base.sys.menu.entity.Menu;
import com.wh.base.sys.role.service.RoleService;
import com.wh.base.sys.user.entity.User;
import com.wh.base.sys.user.service.UserService;
import com.wh.base.util.PwdUtil;
import com.wh.base.util.R;
import com.wh.base.util.RedisUtil;
import com.wh.base.util.StringUtil;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.json.JSONUtil;
import io.swagger.annotations.ApiOperation;

/**
 * <p>
 * 用户登录,登出控制
 * </p>
 *
 * @author WangHong
 */
@RestController
public class AuthController {
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private ConfigService configService;
	
	@Autowired
	private RoleService roleService;
	
	@Resource
    private RedisUtil redisUtil;
	
	
	@PostMapping("/api/login")
	@ApiOperationSupport(order = 1)
	@ApiOperation(value = "登录")
	@OperLog(operModul = "登录", operType = "登录" ,operDesc = "用户登录")
	public R login(@Validated LoginForm form){
		
		int errorNum = Integer.parseInt(configService.cfg().get("user.login.error.num"));  //用户登录最大错误次数
		long lockTime = Long.parseLong(configService.cfg().get("user.login.lock.time"));  //用户锁定时间(单位:秒)
		
		String key = "username_"+form.getUsername();
		Integer cacheErrorNum = (Integer)redisUtil.get(key);
		if(cacheErrorNum != null && cacheErrorNum >= errorNum) {
			return R.error("用户已锁定,请"+Math.ceil(lockTime/60)+"分钟后重试");
		}
		
		String pwd = form.getPassword();
		QueryWrapper<User> wrapper=new QueryWrapper<>();
		wrapper.eq("username",form.getUsername()).eq("password", PwdUtil.encryptPwd(pwd));
 		User user = userService.getOne(wrapper);
		Map<String, Object> map = new HashMap<String, Object>();
		
		if(user != null) {
			// 判断用户状态
			String status = user.getStatus();
			if(UserService.USER_STATUS_DISABLE.equals(status)) {
				return R.error("用户已停用");
			}
			
			// 标记当前会话登录的账号id, 并标记是否记住我
			StpUtil.login(user.getId(), StringUtil.isEmpty(form.getRemember()) ? false : true);  
			// 清除登录错误次数
			redisUtil.del(key); 
			// 将用户权限放入缓存中,以map形式存储,方便取值
			redisUtil.set("auth_sign_"+user.getId(), userService.getAuthSignMapByUserId(user.getId()), 0);
			// 将用户菜单放入缓存
			Map<String, List<Menu>>  menuMap = roleService.findMenuByUserId(StpUtil.getLoginIdAsLong());
			List<Map<String, Object>>  menuList = roleService.buildMenuTree(menuMap, "0");
			redisUtil.set("user_menu_"+user.getId(), JSONUtil.toJsonStr(menuList), 0);
			
			map.put("user", userService.simpleUser(user));
			
			
			
		}else {
			// 记录错误次数
			cacheErrorNum = cacheErrorNum == null ? 1 : cacheErrorNum + 1;
			redisUtil.set(key, cacheErrorNum, lockTime);
			if(cacheErrorNum >= errorNum) {
				return R.error("用户已锁定,请"+Math.ceil(lockTime/60)+"分钟后重试");
			}
			
			return R.error("用户名或密码错误,错误"+(errorNum-cacheErrorNum)+"次后用户将被锁定");
		}
		
		return R.ok(map);
	}
	
	
	@GetMapping("/auth/logout")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "登出")
    @SaCheckLogin
    @OperLog(operModul = "登录", operType = "退出" ,operDesc = "用户退出")
    public R logout() {
		// 清除权限缓存
		redisUtil.del("auth_sign_"+StpUtil.getLoginIdAsLong());
		// 清除用户菜单缓存
		redisUtil.del("user_menu_"+StpUtil.getLoginIdAsLong());
		String username = userService.getUser().getUsername();
        StpUtil.logout();
        return R.ok(username+" 退出成功");
    }
	
	@PostMapping("/auth/modifyPwd")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "修改密码")
    @SaCheckLogin
    @OperLog(operModul = "登录", operType = "修改密码" ,operDesc = "用户修改密码")
    public R ModifyPwd(@Validated ModifyPwdForm form) {
		User user = userService.getUser();
		if(!form.getNewPassword().equals(form.getConfirmPassword())) {
			 return R.error("两次新密码输入不一致");
		}
		if(form.getNewPassword().equals(form.getPassword())) {
			return R.error("新密码与原密码不能一致");
		}
		if(!PwdUtil.comparisonPwd(form.getPassword(), user.getPassword())) {
			return R.error("原密码错误");
		}
		user.setPassword(PwdUtil.encryptPwd(form.getNewPassword()));
		userService.saveOrUpdate(user);
		return R.ok("密码修改成功");
    }
	
	/**
	 * 锁屏专用
	 * @param form
	 * @return
	 */
	@PostMapping("/auth/checkPwd")
    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "验证密码是否正确")
    @SaCheckLogin
    @OperLog(operModul = "登录", operType = "验证密码" ,operDesc = "锁屏专用, 验证当前登录用户密码是否正确")
    public R checkPwd(@Validated CheckPwdForm form) {
		User user = userService.getUser();
		if(!PwdUtil.comparisonPwd(form.getPassword(), user.getPassword())) {
			return R.error("密码错误");
		}
		return R.ok("解锁成功");
    }
}
